https://www.tidytextmining.com/
load libraries
library(rtweet)
library(tidyverse)
library(tidytext)
library(wordcloud2)
stop words
head(stopwordslangs)
tweets_tokenized %>%
count(word, sort = TRUE, name = "freq") %>%
filter(!str_detect(word, "^\\@")) %>%
anti_join(stopwordslangs) # anti_join(tidytext::get_stopwords())
Joining, by = "word"
Word frequencies
Calculate word frequency
frequency <- tweets_tokenized %>%
group_by(screen_name) %>%
count(word, sort = TRUE) %>%
left_join(tweets_tokenized %>%
group_by(screen_name) %>%
summarise(total = n())) %>%
mutate(freq = n/total)
`summarise()` ungrouping output (override with `.groups` argument)
Joining, by = "screen_name"
frequency
"This is a nice and tidy data frame but we would actually like to plot those frequencies on the x- and y-axes of a plot, so we will need to use spread() from tidyr make a differently shaped data frame. – https://www.tidytextmining.com/twitter.html
pivot_wider
frequency <- frequency %>%
select(screen_name, word, freq) %>%
pivot_wider(names_from = screen_name, values_from = freq) #, values_fill = 0)
frequency
viz it
tweets_tokenized %>%
# group_by(screen_name) %>%
count(word, sort = TRUE, name = "freq") %>%
head(200) %>%
filter(!str_detect(word, "^\\@")) %>%
anti_join(stopwordslangs) %>%
wordcloud2(size = 2)
Joining, by = "word"
tweets_tokenized %>%
count(word, sort = TRUE, name = "freq") %>%
filter(!str_detect(word, "^\\@")) %>%
slice_head(n = 30) %>%
ggplot(aes(freq, fct_reorder(word, freq))) +
geom_col()

tweets_tokenized %>%
count(word, sort = TRUE, name = "freq") %>%
anti_join(stopwordslangs) %>%
filter(!str_detect(word, "^\\@")) %>%
slice_head(n = 30) %>%
ggplot(aes(freq, fct_reorder(word, freq))) +
geom_col()
Joining, by = "word"

ggplot(frequency, aes(SakuraYamazaki5, HinaYamazaki1)) +
geom_jitter(alpha = 0.1, size = 2.5, width = 0.25, height = 0.25) +
geom_text(aes(label = word), check_overlap = TRUE, vjust = 1.5) +
scale_x_log10(labels = scales::percent_format()) +
scale_y_log10(labels = scales::percent_format()) +
geom_abline(color = "firebrick")

Word Usage
tweets_by_tweeter %>%
summarise(min_date = min(created_at), max_date = max(created_at))
word_ratios <- tweets_tokenized %>%
# filter(screen_name == "CBBCent1" | screen_name == "Adam_Bradford14") %>%
filter(screen_name == "SakuraYamazaki5" | screen_name == "HinaYamazaki1") %>%
filter(!str_detect(word, "^@")) %>%
count(word, screen_name) %>%
group_by(word) %>%
filter(sum(n) >= 2) %>%
ungroup() %>%
pivot_wider(names_from = screen_name, values_from = n, values_fill = 0) %>%
mutate_if(is.numeric, list(~(. + 1) / (sum(.) + 1))) %>%
mutate(logratio = log(SakuraYamazaki5 / HinaYamazaki1)) %>%
arrange(desc(logratio))
word_ratios
equal usage
word_ratios %>%
arrange(abs(logratio))
word_ratios %>%
group_by(logratio < 0) %>%
top_n(15, abs(logratio)) %>%
ungroup() %>%
mutate(word = reorder(word, logratio)) %>%
ggplot(aes(word, logratio, fill = logratio < 0)) +
geom_col() + #show.legend = FALSE) +
coord_flip() +
ylab("log odds ratio (SakuraYamazaki5/HinaYamazaki1)") +
scale_fill_discrete(name = "", labels = c("SakuraYamazaki5", "HinaYamazaki1"))

Term Document Matrix
{r}
# dtm <- DocumentTermMatrix(docs)
dtm2 <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm2)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
d <- d %>%
slice(2:200)
https://www.tidytextmining.com/tfidf.html#the-bind_tf_idf-function
tweet_words <- tweets_by_tweeter %>%
slice_head(n = 50) %>%
select(screen_name, text, status_id, user_id) %>%
unnest_tokens(word, text, token = "tweets") %>%
filter(!str_detect(word, "^\\@")) %>%
filter(!str_detect(word, "^http")) %>%
anti_join(stopwordslangs) %>%
count(word, tweeter = screen_name, sort = TRUE)
Using `to_lower = TRUE` with `token = 'tweets'` may not preserve URLs.
Joining, by = "word"
tweet_words
total_words <- tweet_words %>%
group_by(tweeter) %>%
summarize(total = sum(n)) %>%
arrange(-total)
`summarise()` ungrouping output (override with `.groups` argument)
total_words
tweet_words <- left_join(tweet_words, total_words)
Joining, by = "tweeter"
tweet_words
tweet_words %>%
bind_tf_idf(word, tweeter, n)
tweet_words %>%
# filter(tweeter != "cpsbeingweird") %>%
bind_tf_idf(word, tweeter, n) %>%
arrange(desc(tf_idf)) %>%
mutate(word = factor(word, levels = rev(unique(word)))) %>%
filter(n > 2) %>%
group_by(tweeter) %>%
# top_n(10) %>%
# ungroup() %>%
ggplot(aes(word, tf_idf)) +
geom_col() +
facet_wrap(~ tweeter) +
coord_flip()

LS0tDQp0aXRsZTogIlJ0d2VldCINCnN1YnRpdGxlOiAiYW4gUmZ1biBkZW1vbnN0cmF0aW9uIg0KYXV0aG9yOiAiSm9obiBMaXR0bGUiDQpkYXRlOiAnYHIgU3lzLkRhdGUoKWAnDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vDQoNCiMjIGxvYWQgbGlicmFyaWVzDQoNCmBgYHtyIGxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocnR3ZWV0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHRpZHl0ZXh0KQ0KbGlicmFyeSh3b3JkY2xvdWQyKQ0KYGBgDQoNCg0KDQoNCiMjIEdldCBUd2VldHMgDQoNCnNlYXJjaF90d2VldHMNCmBgYHtyIGdldFR3ZWV0c30NCnR3ZWV0X2NvbGxlY3Rpb24gPC0gc2VhcmNoX3R3ZWV0cygiI2Ftb25ndXNmYW5hcnQiLCBuPTQwMDAsIGxhbmcgPSAiZW4iKQ0KDQp0d2VldF9jb2xsZWN0aW9uLm9yaWcgPC0gdHdlZXRfY29sbGVjdGlvbg0KYGBgDQoNCg0KYGBge3IgcHJvY2VzcyBUd2VldHN9DQp0d2VldF9jb2xsZWN0aW9uIDwtIHR3ZWV0X2NvbGxlY3Rpb24gJT4lIA0KICBmaWx0ZXIoaXNfcmV0d2VldCA9PSAiRkFMU0UiKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCh0ZXh0LCAiZWxlY3Rpb25uaWdodCIpKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdChoYXNodGFncywgImVsZWN0aW9ubmlnaHQiKSkNCg0KdHdlZXRfY29sbGVjdGlvbg0KYGBgDQoNCg0KIyMgVG9rZW5pemUgdHdlZXRzDQoNCmBgYHtyIGNvcnB1czJ2ZWN0b3J9DQp0d2VldHNfYnlfdHdlZXRlciA8LSB0d2VldF9jb2xsZWN0aW9uICU+JSANCiAgZ3JvdXBfYnkoc2NyZWVuX25hbWUpICU+JSANCiAgbXV0YXRlKGxpbmUgPSByb3dfbnVtYmVyKCkpICU+JSANCiAgdW5ncm91cCgpDQoNCnR3ZWV0c19ieV90d2VldGVyICU+JSANCiAgY291bnQoc2NyZWVuX25hbWUsIHNvcnQgPSBUUlVFKQ0KDQojIGdsaW1wc2UodHdlZXRzX2J5X3R3ZWV0ZXIpDQpgYGANCg0KYGBge3J9DQpiYWRfaGFzaHRhZ3MgPC0gdHdlZXRzX2J5X3R3ZWV0ZXIgJT4lIA0KICBzZWxlY3Qoc3RhdHVzX2lkLCBoYXNodGFncykgJT4lIA0KICB1bm5lc3QoaGFzaHRhZ3MpICU+JSANCiAgZmlsdGVyKHN0cl9kZXRlY3QoaGFzaHRhZ3MsIHJlZ2V4KCJlbGVjdGlvbm5pZ2h0IiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfA0KICAgICAgICAgICAjIHN0cl9kZXRlY3QoaGFzaHRhZ3MsIHJlZ2V4KCJlbGVjdGlvbjIwIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfA0KICAgICAgICAgICBzdHJfZGV0ZWN0KGhhc2h0YWdzLCAiMjAyMCIpKSAlPiUgDQogIGRpc3RpbmN0KHN0YXR1c19pZCkNCmJhZF9oYXNodGFncw0KICAjIGdyb3VwX2J5KGhhc2h0YWdzKSAlPiUgDQogICMgc3VtbWFyaXNlKHRvdF9zdGF0dXNfaWQgPSBuKCkpICU+JSANCiAgIyBhcnJhbmdlKC10b3Rfc3RhdHVzX2lkKSAgICAgICAgICAjIEVsZWN0aW9uTmlnaHQgIC8gRWxlY3Rpb24yMDIwDQogICMgY291bnQoaGFzaHRhZ3MsIHNvcnQgPSBUUlVFKQ0KDQp0d2VldHNfYnlfdHdlZXRlciA8LSB0d2VldHNfYnlfdHdlZXRlciAlPiUgDQogIGFudGlfam9pbihiYWRfaGFzaHRhZ3MpDQoNCnR3ZWV0c19ieV90d2VldGVyDQpgYGANCg0KDQoNCj4gIkJlY2F1c2Ugd2UgaGF2ZSBrZXB0IHRleHQgc3VjaCBhcyBoYXNodGFncyBhbmQgdXNlcm5hbWVzIGluIHRoZSBkYXRhc2V0LCB3ZSBjYW7igJl0IHVzZSBhIHNpbXBsZSBhbnRpX2pvaW4oKSB0byByZW1vdmUgc3RvcCB3b3Jkcy4gSW5zdGVhZCwgd2UgY2FuIHRha2UgdGhlIGFwcHJvYWNoIHNob3duIGluIHRoZSBmaWx0ZXIoKSBsaW5lIHRoYXQgdXNlcyBzdHJfZGV0ZWN0KCkgZnJvbSB0aGUgc3RyaW5nciBwYWNrYWdlLiAtLSBodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vdHdpdHRlci5odG1sDQoNCg0KYGBge3IgdG9rZW5pemVkIHR3ZWV0c30NCnR3ZWV0c190b2tlbml6ZWQgPC0gdHdlZXRzX2J5X3R3ZWV0ZXIgJT4lIA0KICBzZWxlY3QodGV4dCwgc2NyZWVuX25hbWUsIGxpbmUpICU+JSANCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0LCB0b2tlbiA9ICJ0d2VldHMiKSAlPiUNCiAgZmlsdGVyKCF3b3JkICVpbiUgc3RvcF93b3JkcyR3b3JkLA0KICAgICAgICAgIXdvcmQgJWluJSBzdHJfcmVtb3ZlX2FsbChzdG9wX3dvcmRzJHdvcmQsICInIiksDQogICAgICAgICBzdHJfZGV0ZWN0KHdvcmQsICJbYS16XSIpKSANCg0KdHdlZXRzX3Rva2VuaXplZA0KYGBgDQoNCiMjIHN0b3Agd29yZHMNCg0KYGBge3J9DQpoZWFkKHN0b3B3b3Jkc2xhbmdzKQ0KYGBgDQoNCg0KYGBge3J9DQp0d2VldHNfdG9rZW5pemVkICU+JSANCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUsIG5hbWUgPSAiZnJlcSIpICU+JSANCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsICJeXFxAIikpICU+JSANCiAgYW50aV9qb2luKHN0b3B3b3Jkc2xhbmdzKSAgICAgICAgICAgIyBhbnRpX2pvaW4odGlkeXRleHQ6OmdldF9zdG9wd29yZHMoKSkNCmBgYA0KDQoNCg0KDQojIyBXb3JkIGZyZXF1ZW5jaWVzDQoNCiMjIyBDYWxjdWxhdGUgd29yZCBmcmVxdWVuY3kNCg0KYGBge3J9DQpmcmVxdWVuY3kgPC0gdHdlZXRzX3Rva2VuaXplZCAlPiUgDQogIGdyb3VwX2J5KHNjcmVlbl9uYW1lKSAlPiUgDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUgDQogIGxlZnRfam9pbih0d2VldHNfdG9rZW5pemVkICU+JSANCiAgICAgICAgICAgICAgZ3JvdXBfYnkoc2NyZWVuX25hbWUpICU+JSANCiAgICAgICAgICAgICAgc3VtbWFyaXNlKHRvdGFsID0gbigpKSkgJT4lDQogIG11dGF0ZShmcmVxID0gbi90b3RhbCkNCg0KZnJlcXVlbmN5DQpgYGANCg0KPiAiVGhpcyBpcyBhIG5pY2UgYW5kIHRpZHkgZGF0YSBmcmFtZSBidXQgd2Ugd291bGQgYWN0dWFsbHkgbGlrZSB0byBwbG90IHRob3NlIGZyZXF1ZW5jaWVzIG9uIHRoZSB4LSBhbmQgeS1heGVzIG9mIGEgcGxvdCwgc28gd2Ugd2lsbCBuZWVkIHRvIHVzZSBzcHJlYWQoKSBmcm9tIHRpZHlyIG1ha2UgYSBkaWZmZXJlbnRseSBzaGFwZWQgZGF0YSBmcmFtZS4gLS0gaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3R3aXR0ZXIuaHRtbA0KDQpwaXZvdF93aWRlcg0KDQpgYGB7cn0NCmZyZXF1ZW5jeSA8LSBmcmVxdWVuY3kgJT4lIA0KICBzZWxlY3Qoc2NyZWVuX25hbWUsIHdvcmQsIGZyZXEpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNjcmVlbl9uYW1lLCB2YWx1ZXNfZnJvbSA9IGZyZXEpICMsIHZhbHVlc19maWxsID0gMCkNCg0KZnJlcXVlbmN5IA0KYGBgDQoNCiMjIyB2aXogaXQNCg0KYGBge3Igd29yZC1jbG91ZH0NCnR3ZWV0c190b2tlbml6ZWQgJT4lIA0KICAjIGdyb3VwX2J5KHNjcmVlbl9uYW1lKSAlPiUgDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFLCBuYW1lID0gImZyZXEiKSAlPiUgDQogIGhlYWQoMjAwKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkLCAiXlxcQCIpKSAlPiUgDQogIGFudGlfam9pbihzdG9wd29yZHNsYW5ncykgICU+JSANCiAgd29yZGNsb3VkMihzaXplID0gMikNCg0KYGBgDQpgYGB7ciB3b3JkLWZyZXEgYmFycGxvdCwgZmlnLmhlaWdodD03fQ0KdHdlZXRzX3Rva2VuaXplZCAlPiUgDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFLCBuYW1lID0gImZyZXEiKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkLCAiXlxcQCIpKSAlPiUgDQogIHNsaWNlX2hlYWQobiA9IDMwKSAlPiUgDQogIGdncGxvdChhZXMoZnJlcSwgZmN0X3Jlb3JkZXIod29yZCwgZnJlcSkpKSArDQogIGdlb21fY29sKCkNCg0KdHdlZXRzX3Rva2VuaXplZCAlPiUgDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFLCBuYW1lID0gImZyZXEiKSAlPiUgDQogIGFudGlfam9pbihzdG9wd29yZHNsYW5ncykgJT4lIA0KICBmaWx0ZXIoIXN0cl9kZXRlY3Qod29yZCwgIl5cXEAiKSkgJT4lIA0KICBzbGljZV9oZWFkKG4gPSAzMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKGZyZXEsIGZjdF9yZW9yZGVyKHdvcmQsIGZyZXEpKSkgKw0KICBnZW9tX2NvbCgpDQpgYGANCg0KDQpgYGB7ciB3b3JkX2ZyZXEgcGxvdH0NCmdncGxvdChmcmVxdWVuY3ksIGFlcyhTYWt1cmFZYW1hemFraTUsIEhpbmFZYW1hemFraTEpKSArDQogIGdlb21faml0dGVyKGFscGhhID0gMC4xLCBzaXplID0gMi41LCB3aWR0aCA9IDAuMjUsIGhlaWdodCA9IDAuMjUpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHdvcmQpLCBjaGVja19vdmVybGFwID0gVFJVRSwgdmp1c3QgPSAxLjUpICsNCiAgc2NhbGVfeF9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsNCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsNCiAgZ2VvbV9hYmxpbmUoY29sb3IgPSAiZmlyZWJyaWNrIikNCmBgYA0KDQoNCiMjIFdvcmQgVXNhZ2UNCg0KDQpgYGB7cn0NCnR3ZWV0c19ieV90d2VldGVyICU+JSANCiAgc3VtbWFyaXNlKG1pbl9kYXRlID0gbWluKGNyZWF0ZWRfYXQpLCBtYXhfZGF0ZSA9IG1heChjcmVhdGVkX2F0KSkNCmBgYA0KDQoNCmBgYHtyfQ0Kd29yZF9yYXRpb3MgPC0gdHdlZXRzX3Rva2VuaXplZCAlPiUNCiAgIyBmaWx0ZXIoc2NyZWVuX25hbWUgPT0gIkNCQkNlbnQxIiB8IHNjcmVlbl9uYW1lID09ICJBZGFtX0JyYWRmb3JkMTQiKSAlPiUNCiAgZmlsdGVyKHNjcmVlbl9uYW1lID09ICJTYWt1cmFZYW1hemFraTUiIHwgc2NyZWVuX25hbWUgPT0gIkhpbmFZYW1hemFraTEiKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkLCAiXkAiKSkgJT4lDQogIGNvdW50KHdvcmQsIHNjcmVlbl9uYW1lKSAlPiUNCiAgZ3JvdXBfYnkod29yZCkgJT4lDQogIGZpbHRlcihzdW0obikgPj0gMikgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNjcmVlbl9uYW1lLCB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gMCkgJT4lDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBsaXN0KH4oLiArIDEpIC8gKHN1bSguKSArIDEpKSkgJT4lDQogIG11dGF0ZShsb2dyYXRpbyA9IGxvZyhTYWt1cmFZYW1hemFraTUgIC8gSGluYVlhbWF6YWtpMSkpICU+JQ0KICBhcnJhbmdlKGRlc2MobG9ncmF0aW8pKQ0KDQp3b3JkX3JhdGlvcw0KYGBgDQoNCiMjIyBlcXVhbCB1c2FnZQ0KDQpgYGB7cn0NCndvcmRfcmF0aW9zICU+JSANCiAgYXJyYW5nZShhYnMobG9ncmF0aW8pKQ0KYGBgDQoNCg0KYGBge3Igd29yZC11c2FnZX0NCndvcmRfcmF0aW9zICU+JQ0KICBncm91cF9ieShsb2dyYXRpbyA8IDApICU+JQ0KICB0b3BfbigxNSwgYWJzKGxvZ3JhdGlvKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIGxvZ3JhdGlvKSkgJT4lDQogIGdncGxvdChhZXMod29yZCwgbG9ncmF0aW8sIGZpbGwgPSBsb2dyYXRpbyA8IDApKSArDQogIGdlb21fY29sKCkgKyAjc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBjb29yZF9mbGlwKCkgKw0KICB5bGFiKCJsb2cgb2RkcyByYXRpbyAoU2FrdXJhWWFtYXpha2k1L0hpbmFZYW1hemFraTEpIikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiIiwgbGFiZWxzID0gYygiU2FrdXJhWWFtYXpha2k1IiwgIkhpbmFZYW1hemFraTEiKSkNCmBgYA0KDQoNCiMjIEZhdm9yaXRlcyBhbmQgcmV0d2VldHMNCg0KaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3R3aXR0ZXIuaHRtbCNmYXZvcml0ZXMtYW5kLXJldHdlZXRzDQoNCiMjIENoYW5nZXMgaW4gd29yZCB1c2UNCg0KaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3R3aXR0ZXIuaHRtbCNjaGFuZ2VzLWluLXdvcmQtdXNlDQoNCiMjIFRlcm0gRG9jdW1lbnQgTWF0cml4DQoNCmBgYA0Ke3J9DQojIGR0bSA8LSBEb2N1bWVudFRlcm1NYXRyaXgoZG9jcykgDQoNCmR0bTIgPC0gVGVybURvY3VtZW50TWF0cml4KGNvcnB1cykNCm0gPC0gYXMubWF0cml4KGR0bTIpDQp2IDwtIHNvcnQocm93U3VtcyhtKSxkZWNyZWFzaW5nPVRSVUUpDQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikNCg0KZCA8LSBkICU+JSANCiAgc2xpY2UoMjoyMDApDQoNCmBgYA0KDQpodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vdGZpZGYuaHRtbCN0aGUtYmluZF90Zl9pZGYtZnVuY3Rpb24NCg0KYGBge3J9DQp0d2VldF93b3JkcyA8LSB0d2VldHNfYnlfdHdlZXRlciAlPiUgDQogIHNsaWNlX2hlYWQobiA9IDUwKSAlPiUgDQogIHNlbGVjdChzY3JlZW5fbmFtZSwgdGV4dCwgc3RhdHVzX2lkLCB1c2VyX2lkKSAlPiUgIA0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQsIHRva2VuID0gInR3ZWV0cyIpICU+JSANCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsICJeXFxAIikpICU+JQ0KICBmaWx0ZXIoIXN0cl9kZXRlY3Qod29yZCwgIl5odHRwIikpICU+JQ0KICBhbnRpX2pvaW4oc3RvcHdvcmRzbGFuZ3MpICAlPiUgDQogIGNvdW50KHdvcmQsIHR3ZWV0ZXIgPSBzY3JlZW5fbmFtZSwgc29ydCA9IFRSVUUpDQoNCg0KdHdlZXRfd29yZHMNCg0KdG90YWxfd29yZHMgPC0gdHdlZXRfd29yZHMgJT4lDQogIGdyb3VwX2J5KHR3ZWV0ZXIpICU+JQ0KICBzdW1tYXJpemUodG90YWwgPSBzdW0obikpICU+JSANCiAgYXJyYW5nZSgtdG90YWwpDQoNCnRvdGFsX3dvcmRzDQoNCnR3ZWV0X3dvcmRzIDwtIGxlZnRfam9pbih0d2VldF93b3JkcywgdG90YWxfd29yZHMpDQoNCnR3ZWV0X3dvcmRzDQpgYGANCg0KYGBge3J9DQp0d2VldF93b3JkcyAlPiUgDQogIGJpbmRfdGZfaWRmKHdvcmQsIHR3ZWV0ZXIsIG4pDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fQ0KdHdlZXRfd29yZHMgJT4lIA0KICAjIGZpbHRlcih0d2VldGVyICE9ICJjcHNiZWluZ3dlaXJkIikgJT4lIA0KICBiaW5kX3RmX2lkZih3b3JkLCB0d2VldGVyLCBuKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh0Zl9pZGYpKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gZmFjdG9yKHdvcmQsIGxldmVscyA9IHJldih1bmlxdWUod29yZCkpKSkgJT4lIA0KICBmaWx0ZXIobiA+IDIpICU+JSANCiAgZ3JvdXBfYnkodHdlZXRlcikgJT4lDQogICMgdG9wX24oMTApICU+JQ0KICAjIHVuZ3JvdXAoKSAlPiUgDQogIGdncGxvdChhZXMod29yZCwgdGZfaWRmKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+IHR3ZWV0ZXIpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KDQoNCg0KDQojIyBSZXNvdXJjZSBsaXN0DQoNCi0gaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL3RleHQtbWluaW5nLWFuZC13b3JkLWNsb3VkLWZ1bmRhbWVudGFscy1pbi1yLTUtc2ltcGxlLXN0ZXBzLXlvdS1zaG91bGQta25vdw0KDQotIGh0dHA6Ly9hbnRvbmlvLWZlcnJhcm8uZXUucG4vd29yZC1jbG91ZHMtaW4tci1wYWNrYWdlcy13b3JkY2xvdWQyLWFuZC10bS8NCg0KLSBodHRwczovL2pybm9sZC5naXRodWIuaW8vcXNzLXRpZHkvZGlzY292ZXJ5Lmh0bWwjdGV4dHVhbC1kYXRhDQoNCi0gaHR0cHM6Ly9yc3R1ZGlvLXB1YnMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vMzE4NjdfODIzNjk4N2NmMGE4NDQ0ZTk2MmNjZDJhZWM0NmQ5YzMuaHRtbA0KDQotIG9mIGxlc3MgdXNlDQoNCiAgICAtIGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vTWFuaXB1bGF0aW5nX2RhdGEvQ29udmVydGluZ19iZXR3ZWVuX2RhdGFfZnJhbWVzX2FuZF9jb250aW5nZW5jeV90YWJsZXMvDQogICAgLSBodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS9ob3ctdG8tZ2V0LXRoZS1mcmVxdWVuY3ktdGFibGUtb2YtYS1jYXRlZ29yaWNhbC12YXJpYWJsZS1hcy1hLWRhdGEtZnJhbWUtaW4tci8NCiAgICAtIGh0dHBzOi8vd3d3LnF1b3JhLmNvbS9Ib3ctZG8tSS1nZXQtYS1mcmVxdWVuY3ktY291bnQtYmFzZWQtb24tdHdvLWNvbHVtbnMtdmFyaWFibGVzLWluLWFuLVItZGF0YWZyYW1lDQogICAgLSBodHRwczovL3d3dy5xdW9yYS5jb20vSG93LWRvLXlvdS1jcmVhdGUtYS1jb3JwdXMtZnJvbS1hLWRhdGEtZnJhbWUtaW4tUg0KICAgIA0KDQo=